<script setup lang="ts">
import { wadouri } from '@cornerstonejs/dicom-image-loader';
import { onMounted, reactive, ref } from 'vue';
import { convertMultiframeImageIds, prefetchMetadataInformation } from '@/helpers/dicom';
import dicomParser from 'dicom-parser';
import type { IToolGroup } from '@cornerstonejs/tools/dist/cjs/types';
import { MouseBindings, KeyboardBindings } from '@cornerstonejs/tools/dist/cjs/enums';
import { StackScrollMouseWheelTool  } from '@cornerstonejs/tools'
import { cache, RenderingEngine, type Types, Enums } from '@cornerstonejs/core';
import { ViewportType } from '@cornerstonejs/core/src/enums';
import { onBeforeRouteLeave } from 'vue-router';
// import { drawRect, getSvgDrawingHelper } from '@cornerstonejs/tools/dist/cjs/drawingSvg';
// import { CanvasCoordinates } from '@cornerstonejs/tools/dist/cjs/types';
import {
  addTool,
  AngleTool, ArrowAnnotateTool, BidirectionalTool, CircleROITool, EllipticalROITool, LengthTool, ProbeTool, RectangleROITool, 
  ZoomTool, PanTool, WindowLevelTool,
  removeTool, synchronizers,
  ToolGroupManager
} from '@cornerstonejs/tools';
// import { parseTXT, readFile } from './util/parsetxt';
import { parseTXT, readFile } from '../util/parsetxt';
import type { ParsedData } from '../util/parsetxt';


let maxIndex = ref(100)
let currentIndex = ref(0)
const { createImageSliceSynchronizer } = synchronizers;
const { IMAGE_RENDERED } = Enums.Events;
const toolsNames = [
  LengthTool.toolName,
  RectangleROITool.toolName,
  EllipticalROITool.toolName,
  CircleROITool.toolName,
  BidirectionalTool.toolName,
  AngleTool.toolName,
  ArrowAnnotateTool.toolName
];
const toolGroupId = 'fileUploadWIthToolGroup';
let dicomFiles = ref<File[] | null>(null);
const divTag = ref<HTMLDivElement | null>(null);
const returnTag = ref<HTMLDivElement | null>(null);

const txtData = ref<ParsedData | null>(null);
const getPatient = ref<boolean | null>(false);
const patientInfo = reactive({
  patientName: '',
  patientID: '',
  patientBirthDate: '',
  patientSex: '',
  patientAge: ''
});

const pageInfo = ref('');


// Instantiate a rendering engine
const renderingEngineId = 'myRenderingEngine';
const returnrenderingEngineId = 'myreturnRenderingEngine';

const renderingEngine = reactive(new RenderingEngine(renderingEngineId));
const returnrenderingEngine = reactive(new RenderingEngine(returnrenderingEngineId));

const viewport = ref<Types.IViewport>();
const returnviewport = ref<Types.IViewport>();

const selectedToolName = ref<string>(toolsNames[0]);
let totalPage = ref<number>(0);

const run = async () => {
  const content = divTag.value;
  const element = document.createElement('div');
  
  element.oncontextmenu = (e) => e.preventDefault();
  // element.style.width = '1200px';
  const halfScreenWidth = window.innerWidth / 2;
  const ScreenHeight = window.innerHeight / 2;
  element.style.width = `${1 * halfScreenWidth}px`;
  element.style.height = `${1.6 * ScreenHeight}px`;
  content!.appendChild(element);


  const returncontent = returnTag.value;
  const returnelement = document.createElement('div');
  returnelement.oncontextmenu = (e) => e.preventDefault();
  returnelement.style.width = `${1 * halfScreenWidth}px`;
  returnelement.style.height = `${1.6 * ScreenHeight}px`;
  returncontent!.appendChild(returnelement);

  // Add tools to Cornerstone3D
  addTool(LengthTool);
  addTool(ProbeTool);
  addTool(RectangleROITool);
  addTool(EllipticalROITool);
  addTool(CircleROITool);
  addTool(BidirectionalTool);
  addTool(AngleTool);
  addTool(ArrowAnnotateTool);
  addTool(StackScrollMouseWheelTool);
  addTool(ZoomTool);
  addTool(PanTool);
  addTool(WindowLevelTool);

  // Define a tool group, which defines how mouse events map to tool commands for
  // Any viewport using the group
  const toolGroup = ToolGroupManager.createToolGroup(toolGroupId) as IToolGroup;

  // Add tools to the tool group
  toolGroup.addTool(LengthTool.toolName);
  toolGroup.addTool(ProbeTool.toolName);
  toolGroup.addTool(RectangleROITool.toolName);
  toolGroup.addTool(EllipticalROITool.toolName);
  toolGroup.addTool(CircleROITool.toolName);
  toolGroup.addTool(BidirectionalTool.toolName);
  toolGroup.addTool(AngleTool.toolName);
  toolGroup.addTool(ArrowAnnotateTool.toolName);
  toolGroup.addTool(StackScrollMouseWheelTool.toolName, { loop: true });
  toolGroup.addTool(ZoomTool.toolName);
  toolGroup.addTool(PanTool.toolName);
  toolGroup.addTool(WindowLevelTool.toolName);

  // Set the initial state of the tools, here all tools are active and bound to
  // Different mouse inputs
  toolGroup.setToolActive(LengthTool.toolName, {
    bindings: [
      {
        mouseButton: MouseBindings.Primary, // Left Click
      },
    ],
  });
  toolGroup.setToolActive(StackScrollMouseWheelTool.toolName, {
    bindings: []
  });
  toolGroup.setToolActive(ZoomTool.toolName, {
    bindings: [
      {
        modifierKey: KeyboardBindings.Ctrl,
        mouseButton: MouseBindings.Primary,
      },
    ]
  });
  toolGroup.setToolActive(PanTool.toolName, {
    bindings: [
      {
        modifierKey: KeyboardBindings.Alt,
        mouseButton: MouseBindings.Primary,
      },
    ]
  });
  toolGroup.setToolActive(WindowLevelTool.toolName, {
    bindings: [
      {
        modifierKey: KeyboardBindings.ShiftCtrl,
        mouseButton: MouseBindings.Primary,
      },
    ]
  });
  toolGroup.setToolActive(ProbeTool.toolName, {
    bindings: [
      {
        modifierKey: KeyboardBindings.ShiftAlt,
        mouseButton: MouseBindings.Primary,
      },
    ]
  });

  // We set all the other tools passive here, this means that any state is rendered, and editable
  // But aren't actively being drawn (see the toolModes example for information)
  toolGroup.setToolPassive(RectangleROITool.toolName);
  toolGroup.setToolPassive(EllipticalROITool.toolName);
  toolGroup.setToolPassive(CircleROITool.toolName);
  toolGroup.setToolPassive(BidirectionalTool.toolName);
  toolGroup.setToolPassive(AngleTool.toolName);
  toolGroup.setToolPassive(ArrowAnnotateTool.toolName);

  // Create a stack viewport
  const viewportId = 'CT_STACK_20230110';
  const viewportInput = {
    viewportId,
    type: ViewportType.STACK,
    element,
    // defaultOptions: {
    //   background: <Types.Point3> [0.2, 0, 0.2],
    // },
  };
  renderingEngine.enableElement(viewportInput);

  const returnviewportId = 'CT_STACK_return_viewport';
  const returnviewportInput = {
    viewportId: returnviewportId,
    type: ViewportType.STACK,
    element: returnelement,
    // defaultOptions: {
    //   background: <Types.Point3> [0.2, 0, 0.2],
    // },
  };
  returnrenderingEngine.enableElement(returnviewportInput);


  // Get the stack viewport that was created
  viewport.value = <Types.IStackViewport> renderingEngine.getViewport(viewportId);
  returnviewport.value = <Types.IStackViewport> returnrenderingEngine.getViewport(returnviewportId);

  toolGroup.addViewport(viewportId, renderingEngineId);
  toolGroup.addViewport(returnviewportId, returnrenderingEngineId);

  // 在这里加入监听器
  element.addEventListener(IMAGE_RENDERED, ((
    evt: Types.EventTypes.ImageRenderedEvent
  ) => {
    let page = viewport.value!.getCurrentImageIdIndex();
    currentIndex.value = page + 1;
    // returnviewport.value!.setImageIdIndex(currentIndex.value)
    drawInfo(divTag.value, page);
  }) as EventListener);

};

const onChangeFile = (event: Event) => {
  const files = (event.target as HTMLInputElement).files;
  dicomFiles.value = files;
  maxIndex.value = files.length;
  if (!files) {
    return;
  }
  const imageIds = [];
  for (let i = 0; i < files.length; i++){
    imageIds[i] = wadouri.fileManager.add(files[i]);
  }
  totalPage.value = files.length
  loadAndViewImage(imageIds);
  loadAndReturnViewImage(imageIds);
};

const loadAndViewImage = async (imageIds: string[]) => {
  if (!viewport.value) {
    return;
  }

  await prefetchMetadataInformation(imageIds);
  const stack = convertMultiframeImageIds(imageIds);

  // @ts-ignore - Set the stack on the viewport
  viewport.value.setStack(stack).then(() => {
    viewport.value!.render();
  });
  // await viewport.value.setStack(stack);
  // viewport.value!.render();
};

const loadAndReturnViewImage = async (imageIds: string[]) => {
  if (!returnviewport.value) {
    return;
  }

  await prefetchMetadataInformation(imageIds);
  const stack = convertMultiframeImageIds(imageIds);

  // @ts-ignore - Set the stack on the viewport
  returnviewport.value.setStack(stack).then(() => {
    returnviewport.value!.render();
  });
};

// 读取当前页的医生信息
const getPatientInfo = async (page: number) => {
  // 获取患者信息
  getPatient.value = true;
  const arrayBuffer = await dicomFiles.value[page].arrayBuffer();
  const byteArray = new Uint8Array(arrayBuffer);
  const dataSet = dicomParser.parseDicom(byteArray);
  // if (!dataSet) return {};

  const patientName = dataSet.string('x00100010') || 'N/A';
  const patientID = dataSet.string('x00100020') || 'N/A';
  let patientBirthDate = dataSet.string('x00100030') || 'N/A';
  let patientSex = dataSet.string('x00100040') || 'N/A';

  let patientAge = dataSet.string('x00101010') || 'N/A';
  const age = parseInt(patientAge.slice(0, 3), 10);
  const unit = patientAge.slice(3);
  let ageInYears: number;

  if (patientBirthDate.length !== 8) {
    return 'Invalid date';
  }

  const year = patientBirthDate.slice(0, 4);
  const month = patientBirthDate.slice(4, 6);
  const day = patientBirthDate.slice(6, 8);

  switch (unit) {
    case 'Y':
      ageInYears = age;
      break;
    case 'M':
      ageInYears = age / 12;
      break;
    case 'W':
      ageInYears = age / 52;
      break;
    case 'D':
      ageInYears = age / 365;
      break;
    default:
      console.log('Unknown age unit.');
      ageInYears = NaN;
  }
  patientBirthDate = `${year}-${month}-${day}`;
  patientSex = patientSex == 'M' ? '男' : '女';
  patientAge = ageInYears.toString();
  return {
    patientName, 
    patientID, 
    patientBirthDate, 
    patientSex, 
    patientAge
  };
}

// 在画布上写相关信息的函数
const drawInfo = async (element : HTMLDivElement, page: number) => {
  const { patientName, patientID, patientBirthDate, patientSex, patientAge } = await getPatientInfo(page);
  pageInfo.value = `${page + 1} / ${totalPage.value}`;
  patientInfo.patientID = patientID;
  patientInfo.patientName = patientName;
  patientInfo.patientBirthDate = patientBirthDate;
  patientInfo.patientSex = patientSex;
  patientInfo.patientAge = patientAge;

  // 画框
  const context = viewport.value!.canvas.getContext('2d');
  if (!context) {
    throw new Error('Unable to get canvas context');
  }

  const slices = txtData.value.slices;
  for(let i = 0; i < slices.length; i ++) {
    const item = slices[i];
    const slice = item.slice;
    const leftX = item.leftX;
    const leftY = item.leftY;
    const rightX = item.rightX;
    const rightY = item.rightY;
    if (dicomFiles.value.length - 1 - slice === page) {
      // 画框
      // const [x1, y1] = viewport.value.worldToCanvas([leftX, leftY, page])
      // const [x2, y2] = viewport.value.worldToCanvas([rightX, rightY, page])
      context.fillStyle = 'rgba(203,195,145,0.5)';
      context.strokeStyle = 'blue';
      
      // 计算矩形的宽度和高度
      const width = Math.abs(leftX - rightX);
      const height = Math.abs(leftY - rightY);
      console.log(width, height);
      console.log(leftX, leftY, rightX, rightY);
      context.fillRect(0, 0, width, height);
    }
  }
  // console.log('zoom', viewport.value!.getZoom());
}

const inputSlider = async () => {
  await viewport.value;
  await returnviewport.value;
  // console.log('sx', viewport.value!.sx)
  viewport.value!.setImageIdIndex(currentIndex.value - 1);
  // viewport.value.setImageIdIndex(currentIndex.value);
  returnviewport.value!.setImageIdIndex(currentIndex.value - 1);
}

const uploadTxt = async (event: Event) => {
  const file = (event.target as HTMLInputElement).files;
  if (!file) {
    return;
  }
  
  try {
    const content = await readFile(file[0]);
    txtData.value = parseTXT(content);
  } catch (e) {
    console.error('Error reading file: ', e);
  }
};

const onSelectChange = (event: Event) => {
  const newToolName = (event.target as HTMLSelectElement).value;
  const toolGroup = ToolGroupManager.getToolGroup(toolGroupId);
  if (!toolGroup) {
    return;
  }
  toolGroup.setToolActive(newToolName, {
    bindings: [
      {
        mouseButton: MouseBindings.Primary, // Left Click
      }
    ]
  });
  toolGroup.setToolPassive(selectedToolName.value);
  selectedToolName.value = newToolName;
};


onMounted(run);

onBeforeRouteLeave(() => {
  cache.purgeCache();
  ToolGroupManager.destroyToolGroup(toolGroupId);
  removeTool(LengthTool);
  removeTool(ProbeTool);
  removeTool(RectangleROITool);
  removeTool(EllipticalROITool);
  removeTool(CircleROITool);
  removeTool(BidirectionalTool);
  removeTool(AngleTool);
  removeTool(ArrowAnnotateTool);
  removeTool(StackScrollMouseWheelTool);
  removeTool(ZoomTool);
  removeTool(PanTool);
  removeTool(WindowLevelTool);
  renderingEngine.destroy();
  returnrenderingEngine.destroy();
});
</script>

<template>
  <div>
    <div>
      <el-select
        name="tools"
        @change="onSelectChange"
        placeholder="请选择要使用的工具"
        style="width: 240px; margin-left: 10px;"
      >
        <el-option
          v-for="toolName in toolsNames"
          :key="toolName"
        >
          {{ toolName }}
        </el-option>
      </el-select>
      <input
        class="file-input"
        type="file"
        @change="onChangeFile"
        webkitdirectory multiple
      />
      <div>
        <el-text>
          鼠标滚动：翻转浏览影响&nbsp;&nbsp;
          Ctrl+鼠标右键：放大/缩小&nbsp;&nbsp; 
          Alt+拖动：移动图像&nbsp;&nbsp;
          shitf+ctrl+鼠标右键：改变图像窗位<br/>
          鼠标的左右滑动和上下滑动分别用于调整窗口宽度(Window Width, WW)和窗口中心(Window Center, WC)<br/>
          Shift+Alt+鼠标左键:显示ct值
        </el-text>
      </div>
      <div class="container">
        <el-row>
          <el-col :span="24">
            <div class="grid-content">
              <el-slider
                v-model="currentIndex"
                :min="1"
                :max="maxIndex"
                @input="inputSlider"
              ></el-slider>
            </div>
            
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <div ref="divTag" class="div-item">
            <div v-if="getPatient === true" class="info-top-right">
              <p>患者ID: {{ patientInfo.patientID }}</p>
              <p>姓名: {{ patientInfo.patientName }}</p>
              <p>生日: {{ patientInfo.patientBirthDate }}</p>
              <p>性别: {{ patientInfo.patientSex }}</p>
              <p>年龄: {{ patientInfo.patientAge }}</p>
            </div>
            <div v-if="pageInfo != ''" class="info-bottom-left">
              <p>{{ pageInfo }}</p>
            </div>
          </div>
          </el-col>
          <el-col :span="12">
            <div ref="returnTag" class="div-item"></div>
          </el-col>
        </el-row>

      </div>
      
      <input
        class="file-input"
        type="file"
        accept=".txt"
        @change="uploadTxt"
      />
    </div>
  </div>
</template>

<style scoped lang="scss">
.info-top-right {
  position: absolute;
  top: 15px;
  right: 50px;
  text-align: right;
  z-index: 100;
  color: white;
}

.info-bottom-left {
  position: absolute;
  bottom: 15px;
  left: 20px;
  z-index: 100;
  color: white;
}

.file-input {
  margin-bottom: 1rem;
}

.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px;
}
.grid-content {
  margin-left: 20px;
  margin-right: 20px;
}
select {
  margin-bottom: 8px;
}
</style>
